<template>
  <component
    ref="formEl"
    :is="formRegister && !wRadios ? 'w-form-element' : 'div'"
    v-bind="formRegister && { validators, inputValue, disabled }"
    v-model:valid="valid"
    @reset="
      $emit('update:modelValue', (inputValue = null));
      $emit('input', null);
    "
    :class="classes"
    ><input
      ref="input"
      :id="`w-radio--${_.uid}`"
      type="radio"
      :name="inputName"
      :checked="inputValue || null"
      :disabled="disabled || null"
      :required="required || null"
      @focus="$emit('focus', $event)"
      @change="
        onInput(
          $event
        ) /* Edge doesn't fire input on checkbox/radio/select change */
      "
      :aria-checked="inputValue || 'false'"
      role="radio"
    /><template v-if="hasLabel && labelOnLeft"
      ><label
        class="w-radio__label w-form-el-shakable pr2"
        v-if="$slots.default"
        :for="`w-radio--${_.uid}`"
      >
        <slot></slot> </label
      ><label
        class="w-radio__label w-form-el-shakable pr2"
        v-else-if="label"
        :for="`w-radio--${_.uid}`"
        v-html="label"
      ></label
    ></template>
    <div
      class="w-radio__input"
      @click="
        $refs.input.focus();
        $refs.input.click();
      "
      :class="this.color"
    ></div>
    <template v-if="hasLabel && !labelOnLeft"
      ><label
        class="w-radio__label w-form-el-shakable pl2"
        v-if="$slots.default"
        :for="`w-radio--${_.uid}`"
      >
        <slot></slot> </label
      ><label
        class="w-radio__label w-form-el-shakable pl2"
        v-else-if="label"
        :for="`w-radio--${_.uid}`"
        v-html="label"
      ></label
    ></template>
  </component>
</template>

<script>
import {
  ref,
  reactive,
  computed,
  watch,
  getCurrentInstance,
  inject
} from "vue";
export default {
  name: "w-radio",

  props: {
    modelValue: { default: false }, // v-model to check or uncheck.
    // When `value` is taken by a v-model and multiple w-radio are plugged on
    // the same v-model, this allows returning a custom value to the v-model.
    returnValue: {},
    label: { type: String },
    labelOnLeft: { type: Boolean },
    color: { type: String, default: "primary" },
    noRipple: { type: Boolean },
    // Also name, disabled, readonly, required and validators in the mixin.
    name: { type: String }, // When sending data through form.
    disabled: { type: Boolean },
    required: { type: Boolean },
    validators: { type: Array }
  },

  emits: ["input", "update:modelValue", "focus"],
  setup(props, ctx) {
    const instance = getCurrentInstance();
    const inputValue = ref(false);
    const ripple = reactive({
      start: false,
      end: false,
      timeout: null
    });
    const valid = ref(null);
    const wRadios = inject("wRadios", { default: null });
    const formRegister = inject("formRegister", { default: null });
    if (props.modelValue !== undefined) {
      toggleFromOutside();
    }
    const hasLabel = computed(() => {
      return props.label || ctx.slots.default;
    });
    const classes = computed(() => {
      return {
        [`w-radio w-radio--${
          inputValue.value ? "checked" : "unchecked"
        }`]: true,
        "w-radio--disabled": props.disabled,
        "w-radio--ripple": ripple.start,
        "w-radio--rippled": ripple.end
      };
    });

    const inputName = computed(() => {
      return (
        props.name || `${instance.type.name}--${instance.type.uid || instance.uid}`
      );
    });

    function toggleFromOutside() {
      inputValue.value =
        props.returnValue !== undefined
          ? props.returnValue === props.modelValue
          : props.modelValue;
    }

    function onInput(e) {
      inputValue.value = e.target.checked; // The source of truth is the radio button.
      const returnValue =
        inputValue.value && props.returnValue !== undefined
          ? props.returnValue
          : inputValue.value;
      ctx.emit("update:modelValue", returnValue);
      ctx.emit("input", returnValue);

      if (!props.noRipple) {
        if (inputValue.value) {
          ripple.start = true;
          ripple.timeout = setTimeout(() => {
            ripple.start = false;
            ripple.end = true;
            setTimeout(() => (ripple.end = false), 100);
          }, 700);
        } else {
          ripple.start = false;
          clearTimeout(ripple.timeout);
        }
      }
    }
    watch(
      () => props.modelValue,
      () => {
        toggleFromOutside();
      }
    );
    return {
      inputValue,
      ripple,
      valid,
      wRadios,
      formRegister,
      hasLabel,
      classes,
      inputName,
      toggleFromOutside,
      onInput
    };
  }
};
</script>
